package main

import (
	"fmt"
	"sort"
)

const (
	ErrorCheckType int = iota
	CaseCheckType
	LogicalCheckType
	MissExpression
	MoreExpression
)

var CheckMessageMap = map[int]string{MissExpression: "缺少了逻辑表达式序列", MoreExpression: "多出了逻辑表达式序列"}

type ExprCheck struct {
	Type       int
	device     string
	action     string
	message    string
	filePath   string
	line       int
	fullStr    string
	expr       *Expression
	target     *Expression
	childCheck []*ExprCheck
}

type ActionCheck struct {
	action    string
	exprCheck []*ExprCheck
}

type Checked struct {
	device  string
	actions []ActionCheck
	Err     []string
}

func NewDefaultExprCheck(tp, line int, filePath, fullStr, device, action string) *ExprCheck {
	return &ExprCheck{
		Type:     tp,
		device:   device,
		action:   action,
		line:     line,
		filePath: filePath,
		fullStr:  fullStr,
	}
}

func NewMessageExprCheck(cType, line int, msg, filePath, fullStr string, target *Expression) *ExprCheck {
	return &ExprCheck{
		Type:     cType,
		message:  msg,
		target:   target,
		line:     line,
		filePath: filePath,
		fullStr:  fullStr,
	}
}

func NewBaseExprCheck(cType, line int, filePath, fullStr string) *ExprCheck {
	return &ExprCheck{
		Type:     cType,
		line:     line,
		filePath: filePath,
		fullStr:  fullStr,
	}
}

func (e *ExprCheck) AppendDiffChild(cType, line int, filePath, fullStr string, target *Expression, exprStr []string) {
	ec := NewMessageExprCheck(cType, line, CheckMessageMap[cType], filePath, fullStr, target)
	ec.expr = &Expression{expr: exprStr}
	ec.expr.Marshal()
	if ec.expr.str == "" {
		return
	}
	e.childCheck = append(e.childCheck, ec)
}

func Check(srcPath, dstPath string) []Checked {
	srcLDM := BuildLogicalData(srcPath)
	dstLDM := BuildLogicalData(dstPath)
	igList := GetIgnoreList("ignore.fil")
	// 正向比对
	CheckedS := checkLine(srcLDM, dstLDM, igList, false)
	// 反向比对， 只查找缺失的设备
	_CheckedS := checkLine(dstLDM, srcLDM, igList, true)
	CheckedS = append(CheckedS, _CheckedS...)
	//fmt.Printf("result:::%v\n", Checkeds)
	return CheckedS
}

func checkLine(sLDM, dLdm LogicalDeviceMap, igList []*Ignore, overturn bool) []Checked {
	var Checkeds []Checked
	var t string
	var devices []string
	for device, _ := range sLDM {
		devices = append(devices, device)
	}
	sort.Strings(devices)

	for _, device := range devices {
		check := Checked{}
		actCheck := ActionCheck{}
		for action, le := range sLDM[device] {
			ok := checkIgnoreList(device, action, le, igList)
			if ok == true {
				continue
			}
			dstLogicExpr, err := dLdm.GetLogicalExpr(device, action)
			if err != nil {
				if overturn == false {
					t = "目标"
				} else {
					t = "源"
				}
				msg := fmt.Sprintf("[%s:%d]\n\t设备编号:%s,动作:%s\n\t[%s]%s\n", le.filePath, le.Line, device, action, t, err.Error())
				check.Err = append(check.Err, msg)
				continue
			}
			if overturn == false {
				actCheck.action = action
				actCheck.exprCheck = le.Diff(dstLogicExpr)
				check.actions = append(check.actions, actCheck)
			}
		}
		ok := checkIgnoreList(device, "", nil, igList)
		if ok == true {
			fmt.Println("ok")
		}
		if overturn == false && ok == false {
			check.device = device
			Checkeds = append(Checkeds, check)
		}
	}
	return Checkeds
}

func checkIgnoreList(device, action string, expr *LogicalExpr, igList []*Ignore) bool {
	ok := false
	for i := range igList {
		ok = ok || igList[i].CheckIgnore(device, action, expr)

	}
	return ok
}
